/*! @file
********************************************************************************
<PRE>
模块名       : <DNS解析模块>
文件名       : <dnspacket.cpp>
相关文件     : <dnspacket.h>
文件实现功能 : <解析DNS数据包>
作者         : <张则梁>
版本         : <1.0>
--------------------------------------------------------------------------------
多线程安全性 : <是/否>[，说明]
异常时安全性 : <是/否>[，说明]
--------------------------------------------------------------------------------
备注         : <其它说明>
--------------------------------------------------------------------------------
修改记录 : 
日 期        版本     修改人              修改内容
YYYY/MM/DD   X.Y      <作者或修改者名>    <修改内容>
</PRE>
*******************************************************************************/

#include "dnspacket.h"

/* 构造函数 */
CDnsPacket::CDnsPacket()
    : m_data(NULL)
{
}

/* 析构函数 */
CDnsPacket::~CDnsPacket()
{
}

/* 初始化数据包 */
int32_t CDnsPacket::InitData(uint8_t *data, uint32_t len)
{
    int32_t i = 0;
    int32_t cur_offset = 0;
    
    if ( len < DNS_HDRLEN || NULL == data )
    {
        return E_RET_HEAD_FAIL;
    }
    
    /* 复制数据包 */
    m_dlen = len;
    //m_data = new uint8_t[m_dlen];
    //memcpy(m_data, data, m_dlen);
    m_data = data;
    
    /* 解析包头 */
    __ParserHead();
    
    cur_offset = DNS_HDRLEN;    /* 当前偏移位置 */
    
    //判断合法性 
    if ( m_head_inf.qdcount <= 0 || m_head_inf.qdcount > MAX_RRS_NUM )
    {
        m_head_inf.qdcount = 0;
        return E_RET_FAIL;
    }
    if ( m_head_inf.ancount <= 0 || m_head_inf.ancount > MAX_RRS_NUM )
    {
        m_head_inf.ancount = 0;
    }
    if ( m_head_inf.nscount <= 0 || m_head_inf.nscount > MAX_RRS_NUM )
    {
        m_head_inf.nscount = 0;
    }
    if ( m_head_inf.arcount <= 0 || m_head_inf.arcount > MAX_RRS_NUM )
    {
        m_head_inf.arcount = 0;
    }

    /* 问题信息 */
    for (i=0; i<m_head_inf.qdcount; i++)
    {
        if ( E_RET_FAIL == __GetOneQuestion(&cur_offset, &(m_queries[i])) )
        {
            return E_RET_FAIL;
        }
    }
   
    /* 回答信息 */
    for (i=0; i<m_head_inf.ancount; i++)
    {
        if ( E_RET_FAIL == __GetOneResource(&cur_offset, &(m_answers[i])) )
        {
            return E_RET_FAIL;
        }
    }

    /* 授权信息 */
    for (i=0; i<m_head_inf.nscount; i++)
    {
        if ( E_RET_FAIL == __GetOneResource(&cur_offset, &(m_authors[i])) )
        {
            return E_RET_FAIL;
        }
    }

    /* 附加信息 */
    for (i=0; i<m_head_inf.arcount; i++)
    {
        if ( E_RET_FAIL == __GetOneResource(&cur_offset, &(m_additions[i])) )
        {
            return E_RET_FAIL;
        }
    }

    /* 解析所有RDATA数据 */
    if ( E_RET_FAIL == __ParseAllRdata() )
    {
        return E_RET_FAIL;
    }
    
    return E_RET_SUCCESS;
}

/* 获取头信息结构指针 */
DNS_HEAD_INFO* CDnsPacket::GetHeadInfo()
{
    return &m_head_inf;
}

/* 获取问题信息结构指针 */
DNS_QUESTION_INFO* CDnsPacket::GetQueriesInfo()
{
    return m_queries;
}

/* 获取回答信息结构指针 */
DNS_RESOURCE_INFO* CDnsPacket::GetAnswersInfo()
{
    return m_answers;
}

/* 获取授权信息结构指针 */
DNS_RESOURCE_INFO* CDnsPacket::GetAuthorsInfo()
{
    return m_authors;
}

/* 获取附加信息结构指针 */
DNS_RESOURCE_INFO* CDnsPacket::GetAdditionsInfo()
{
    return m_additions;
}

int32_t CDnsPacket::__ParserHead()
{ 
    memcpy(&m_head_inf, m_data, DNS_HDRLEN);
    m_head_inf.id = ntohs(m_head_inf.id);
    m_head_inf.flag = ntohs(m_head_inf.flag);
    m_head_inf.qdcount = ntohs(m_head_inf.qdcount);
    m_head_inf.ancount = ntohs(m_head_inf.ancount);
    m_head_inf.nscount = ntohs(m_head_inf.nscount);
    m_head_inf.arcount = ntohs(m_head_inf.arcount);
    
    return E_RET_SUCCESS;
}

/* 获取扩展域名 */
int32_t CDnsPacket::__ExpandDnsName(
                                    int32_t *offset,    /* 当前的偏移位置 */
                                    uint8_t *name       /* 解析出来的域名 */
                                    )
{
    int32_t len = -1;
    int32_t cur_offset = *offset;
    uint32_t component_len = 0;
    uint8_t *np = name;
    int8_t poiflag = 0;     /* 是否碰到指针 */
#if 1
    uint32_t poinum = 0;    /* 碰到指针的次数 */
#else
    vector<int32_t> v_pt;
#endif
    uint8_t isroot = 0;     /* 0：错误没进去 1：是根目录 2：非根目录*/

    while ( cur_offset < m_dlen )
    {
        component_len = m_data[cur_offset++];
        if ( 0 == poiflag ) /* 只有在没有碰到指针时才需要增加偏移 */
        {
            *offset += 1;
        }
        if ( 0 == isroot )
        {
            isroot = 1;     /* 进来了就置根 */
        }
        if ( 0 == component_len )
        {
            break;
        }
        if ( 1 == isroot )
        {
            isroot = 2;     /* 下来了就置非根 */
        }

        switch ( component_len & 0xc0 )
        {
        case 0x00:  /* Label */
            if ( np != name )
            {
                *np++ = '.';
                len += 1;
                if ( len + 1 > MAXDNSNAME - 1 )
                {
                    /* 超过最大长度 */
                    return -1;
                }
            }
            while ( (0 != component_len--) && (cur_offset < m_dlen) )
            {
                *np++ = m_data[cur_offset++];
                len += 1;
                if ( len + 1 > MAXDNSNAME - 1 )
                {
                    /* 超过最大长度 */
                    return -1;
                }
                if ( 0 == poiflag )
                {
                    *offset += 1;
                }
            }
            break;
        //case 0x40:  /* Extended label (RFC 2673) */
        //    break;
        case 0xc0:  /* Pointer */
            cur_offset = ((component_len & ~0xc0) << 8) | m_data[cur_offset];
            if ( 0 == poiflag ) /* 只需要碰一次指针，再次碰到一定是已转向后的指针跟本次长度无关 */
            {
                *offset += 1;
                poiflag = 1;    /* 碰到指针了 */
            }
#if 1
            poinum += 1;
            if ( poinum >= 10 )
            {
                /* 碰到10次指针了 认为是死循环指针 */
                //printf("error: too much pointer!\n");
                LOG(INFO) << "error: too much pointer!";
                return -1;
            }
#else
            for (vector<int32_t>::iterator it=v_pt.begin(); it!=v_pt.end(); ++it)
            {
                if ( cur_offset == *it )
                {
                    /* 指针转回到之前的偏移了，死循环 */
                    v_pt.clear();
                    LOG(INFO) << "__ExpandDnsName() error: point loop!";
                    return -1;
                }
            }
            v_pt.push_back(cur_offset);
#endif
            break;
        default:
            //printf("error! component_len & 0xc0=%02x",component_len & 0xc0);
            //LOG(INFO) << "error! component_len & 0xc0=" << (component_len & 0xc0);
            return -1;
            break;
        }
    }
#if 1
#else
    v_pt.clear();
#endif
    
    //访问根目录
    if ( 1 == isroot )
    {
        *np++ = '/';
        len += 1;
    }
    
    if ( -1 != len )
    {
        *np = '\0';
        len += 1;
    }

    if ( 1 != isroot )
    {
        // 是否合法域名
        if ( 0 == IsLegelDomainName((char*)name) )
        {
            return -1;
        }
    }
    
    return len;
}

/* 获取一个问题的信息 */
int32_t CDnsPacket::__GetOneQuestion(
                                    int32_t *offset,
                                    DNS_QUESTION_INFO* queinfo
                                    )
{
    memset(queinfo->name, 0, MAXDNSNAME);
    if ( -1 == __ExpandDnsName(offset, queinfo->name) )
    {
        return E_RET_FAIL;
    }
    
    if ( (*offset) + 4 > m_dlen )
    {
        return E_RET_FAIL;
    }
    /* 查询类型 */
    queinfo->type = m_data[(*offset)++];
    queinfo->type = queinfo->type << 8 | m_data[(*offset)++];
    /* 查询的协议类 */
    queinfo->cls = m_data[(*offset)++];
    queinfo->cls = queinfo->cls << 8 | m_data[(*offset)++];
    
    return E_RET_SUCCESS;
}

/* 从flag中获取QR值 */
uint16_t CDnsPacket::GetQrFromFlag(uint16_t flag)
{
    return flag >> 15;
}

/* 从flag中获取OPCODE值 */
uint16_t CDnsPacket::GetOpcodeFromFlag(uint16_t flag)
{
    return (flag >> 11) & 0x0f;
}

/* 从flag中获取AA值 */
uint16_t CDnsPacket::GetAaFromFlag(uint16_t flag)
{
    return (flag >> 10) & 0x01;
}

/* 从flag中获取TC值 */
uint16_t CDnsPacket::GetTcFromFlag(uint16_t flag)
{
    return (flag >> 9) & 0x01;
}

/* 从flag中获取RD值 */
uint16_t CDnsPacket::GetRdFromFlag(uint16_t flag)
{
    return (flag >> 8) & 0x01;
}

/* 从flag中获取RA值 */
uint16_t CDnsPacket::GetRaFromFlag(uint16_t flag)
{
    return (flag >> 7) & 0x01;
}

/* 从flag中获取RCODE值 */
uint16_t CDnsPacket::GetRcodeFromFlag(uint16_t flag)
{
    return flag & 0x0f;
}

/* 是否合法域名 */
int8_t CDnsPacket::IsLegelDomainName(char *dname)
{
    int32_t i = 0;
    int32_t len = 0;
    
    if ( NULL == dname )
    {
        return 0;
    }
    
    len = strlen(dname);
    if ( len < 1 )
    {
        return 0;
    }
    
    for (i=0; i<len; i++)
    {
        if ( (dname[i] >= '0' && dname[i] <= '9')
            || (dname[i] >= 'A' && dname[i] <= 'Z')
            || (dname[i] >= 'a' && dname[i] <= 'z')
            || (i>0 && '-' == dname[i])
            || (i>0 && '.' == dname[i])
            )
        {
        }
        else
        {
            return 0;
        }
    }
    
    return 1;
}

/* 获取一个资源记录的信息 */
int32_t CDnsPacket::__GetOneResource(
                                    int32_t *offset,
                                    DNS_RESOURCE_INFO* resinfo
                                    )
{
    memset(resinfo->name, 0, MAXDNSNAME);
    if ( -1 == __ExpandDnsName(offset, resinfo->name) )
    {
        return E_RET_FAIL;
    }
    if ( (*offset) + 10 > m_dlen )
    {
        return E_RET_FAIL;
    }
    /* 资源记录的类型 */
    resinfo->type = m_data[(*offset)++];
    resinfo->type = resinfo->type << 8 | m_data[(*offset)++];
    /* RDATA的类 */
    resinfo->cls = m_data[(*offset)++];
    resinfo->cls = resinfo->cls << 8 | m_data[(*offset)++];
    /* 资源记录可以缓存的时间 */
    resinfo->ttl = m_data[(*offset)++];
    resinfo->ttl = resinfo->ttl << 8 | m_data[(*offset)++];
    resinfo->ttl = resinfo->ttl << 8 | m_data[(*offset)++];
    resinfo->ttl = resinfo->ttl << 8 | m_data[(*offset)++];
    /* RDATA的长度 */
    resinfo->rdlen = m_data[(*offset)++];
    resinfo->rdlen = resinfo->rdlen << 8 | m_data[(*offset)++];

    if ( resinfo->rdlen > MAX_RDATA_LEN )
    {
        return E_RET_FAIL;
    }

    /* RDATA的起始位置 */
    resinfo->rdoffset = *offset;
    *offset += resinfo->rdlen;      /* 偏移量移到RDATA */
    
    return E_RET_SUCCESS;
}

/* 解析所用RDATA数据 InitData函数没有解析RDATA数据，调用此接口后才解析RDATA数据 */
int32_t CDnsPacket::__ParseAllRdata()
{
    int32_t i = 0;
    
    /* 回答信息 */
    for (i=0; i<m_head_inf.ancount; i++)
    {
        if ( E_RET_FAIL == __ParseRdata(&(m_answers[i])) )
        {
            return E_RET_FAIL;
        }
    }

    /* 授权信息 */
    for (i=0; i<m_head_inf.nscount; i++)
    {
        if ( E_RET_FAIL == __ParseRdata(&(m_authors[i])) )
        {
            return E_RET_FAIL;
        }
    }

    /* 附加信息 */
    for (i=0; i<m_head_inf.arcount; i++)
    {
        if ( E_RET_FAIL == __ParseRdata(&(m_additions[i])) )
        {
            return E_RET_FAIL;
        }
    }
 
    return E_RET_SUCCESS;
}

/* 解析一个RDATA数据 */
int32_t CDnsPacket::__ParseRdata(DNS_RESOURCE_INFO *resinfo)
{
    int32_t ret = E_RET_FAIL;
    
    if ( C_IN == resinfo->cls )
    {
        switch ( resinfo->type )
        {
        case T_A:
            ret = __Rdata2A(resinfo);
            break;
        case T_NS:
            ret = __Rdata2NS(resinfo);
            break;
        case T_MD:
            ret = __Rdata2MD(resinfo);
            break;
        case T_MF:
            ret = __Rdata2MF(resinfo);
            break;
        case T_CNAME:
            ret = __Rdata2CNAME(resinfo);
            break;
        case T_SOA:
            ret = __Rdata2SOA(resinfo);
            break;
        case T_MB:
            ret = __Rdata2MB(resinfo);
            break;
        case T_MG:
            ret = __Rdata2MG(resinfo);
            break;
        case T_MR:
            ret = __Rdata2MR(resinfo);
            break;
        case T_NULL:
            ret = __Rdata2NULL(resinfo);
            break;
        case T_WKS:
            ret = __Rdata2WKS(resinfo);
            break;
        case T_PTR:
            ret = __Rdata2PTR(resinfo);
            break;
        case T_HINFO:
            ret = __Rdata2HINFO(resinfo);
            break;
        case T_MINFO:
            ret = __Rdata2MINFO(resinfo);
            break;
        case T_MX:
            ret = __Rdata2MX(resinfo);
            break;
        case T_TXT:
            ret = __Rdata2TXT(resinfo);
            break;
        default:
            printf("error __ParseRdata() resinfo->type=%d\n", resinfo->type);
            ret = E_RET_SUCCESS;    /* 其它不解析，正确返回 */
            break;
        }
    }
    else if ( C_CS == resinfo->cls )
    {
        printf("__ParseRdata() C_CS\n");
    }
    else if ( C_CH == resinfo->cls )
    {
        printf("__ParseRdata() C_CH\n");
    }
    else if ( C_HS == resinfo->cls )
    {
        printf("__ParseRdata() C_HS\n");
    }
    else
    {
        printf("error! __ParseRdata() resinfo->cls=%d\n", resinfo->cls);
    }
    
    return ret;
}

/* ----------解析各类RDATA数据begin----------- */
int32_t CDnsPacket::__Rdata2A(DNS_RESOURCE_INFO *resinfo)
{
    uint32_t *pdata = (uint32_t *)&(m_data[resinfo->rdoffset]);
    
    /* 分配相应结构体的内存 */
    //resinfo->rdatainfo = new uint8_t[sizeof(RDATA_FORMAT_A)];
    RDATA_FORMAT_A *pinfo = (RDATA_FORMAT_A *)resinfo->rdatainfo;
    
    /* 32位互联网地址 */
    pinfo->address = *pdata;
    pinfo->address = ntohl(pinfo->address);
    
    return E_RET_SUCCESS;
}

int32_t CDnsPacket::__Rdata2NS(DNS_RESOURCE_INFO *resinfo)
{
    int32_t offset = resinfo->rdoffset;
    
    /* 分配相应结构体的内存 */
    //resinfo->rdatainfo = new uint8_t[sizeof(RDATA_FORMAT_NS)];
    RDATA_FORMAT_NS *pinfo = (RDATA_FORMAT_NS *)resinfo->rdatainfo;
    
    /* 一个<domain-name>，它规定主机，对于指定的类和域，该主机应当是权威的 */
    memset(pinfo->nsdname, 0, MAXDNSNAME);
    if ( -1 == __ExpandDnsName(&offset, pinfo->nsdname) )
    {
        return E_RET_FAIL;
    }
    
    return E_RET_SUCCESS;
}

int32_t CDnsPacket::__Rdata2MD(DNS_RESOURCE_INFO *resinfo)
{
    int32_t offset = resinfo->rdoffset;
    
    /* 分配相应结构体的内存 */
    //resinfo->rdatainfo = new uint8_t[sizeof(RDATA_FORMAT_MDF)];
    RDATA_FORMAT_MDF *pinfo = (RDATA_FORMAT_MDF *)resinfo->rdatainfo;
    
    /* 一个<domain-name>，它规定有该域的邮件代理的主机，该邮件代理应当能够交付该域的邮件 */
    memset(pinfo->madname, 0, MAXDNSNAME);
    if ( -1 == __ExpandDnsName(&offset, pinfo->madname) )
    {
        return E_RET_FAIL;
    }
    
    return E_RET_SUCCESS;
}

int32_t CDnsPacket::__Rdata2MF(DNS_RESOURCE_INFO *resinfo)
{
    int32_t offset = resinfo->rdoffset;
    
    /* 分配相应结构体的内存 */
    //resinfo->rdatainfo = new uint8_t[sizeof(RDATA_FORMAT_MDF)];
    RDATA_FORMAT_MDF *pinfo = (RDATA_FORMAT_MDF *)resinfo->rdatainfo;
    
    /* 一个<domain-name>，它规定有该域的邮件代理的主机，该邮件代理将接收转发到该域的邮件 */
    memset(pinfo->madname, 0, MAXDNSNAME);
    if ( -1 == __ExpandDnsName(&offset, pinfo->madname) )
    {
        return E_RET_FAIL;
    }
    
    return E_RET_SUCCESS;
}

int32_t CDnsPacket::__Rdata2CNAME(DNS_RESOURCE_INFO *resinfo)
{
    int32_t offset = resinfo->rdoffset;
    
    /* 分配相应结构体的内存 */
    //resinfo->rdatainfo = new uint8_t[sizeof(RDATA_FORMAT_CNAME)];
    RDATA_FORMAT_CNAME *pinfo = (RDATA_FORMAT_CNAME *)resinfo->rdatainfo;
    
    /* 一个<domain-name>，它规定所有者的正则或主要名称。该所有者名称是别名 */
    memset(pinfo->cname, 0, MAXDNSNAME);
    if ( -1 == __ExpandDnsName(&offset, pinfo->cname) )
    {
        return E_RET_FAIL;
    }
    
    return E_RET_SUCCESS;
}

int32_t CDnsPacket::__Rdata2SOA(DNS_RESOURCE_INFO *resinfo)
{
    int32_t offset = resinfo->rdoffset;
    uint32_t *pdata = NULL;
    
    /* 分配相应结构体的内存 */
    //resinfo->rdatainfo = new uint8_t[sizeof(RDATA_FORMAT_SOA)];
    RDATA_FORMAT_SOA *pinfo = (RDATA_FORMAT_SOA *)resinfo->rdatainfo;
    
    /* 名称服务器的<domain-name>，该名称服务器是这个区域的数据的起源或主要源 */
    memset(pinfo->mname, 0, MAXDNSNAME);
    if ( -1 == __ExpandDnsName(&offset, pinfo->mname) )
    {
        return E_RET_FAIL;
    }
    
    /* 一个<domain-name>，它规定负责这个区域的个人的邮箱 */
    memset(pinfo->rname, 0, MAXDNSNAME);
    if ( -1 == __ExpandDnsName(&offset, pinfo->rname) )
    {
        return E_RET_FAIL;
    }
    
    pdata = (uint32_t *)&(m_data[offset]);
    
    /* 该区域的原始副本的无正负号32位版本号 */
    pinfo->serial = *pdata++;
    pinfo->serial = ntohl(pinfo->serial);
    
    /* 区域应当被刷新前的32位时间间隔 */
    pinfo->refresh = *pdata++;
    pinfo->refresh = ntohl(pinfo->refresh);
    
    /* 应当重试失败的刷新前，应当消逝的32位时间间隔 */
    pinfo->retry = *pdata++;
    pinfo->retry = ntohl(pinfo->retry);
    
    /* 32 位时间值，它规定时间间隔的上限 */
    pinfo->expire = *pdata++;
    pinfo->expire = ntohl(pinfo->expire);
    
    /* 无正负号32位最小值TTL字段 */
    pinfo->minimum = *pdata++;
    pinfo->minimum = ntohl(pinfo->minimum);
    
    return E_RET_SUCCESS;
}

int32_t CDnsPacket::__Rdata2MB(DNS_RESOURCE_INFO *resinfo)
{
    int32_t offset = resinfo->rdoffset;
    
    /* 分配相应结构体的内存 */
    //resinfo->rdatainfo = new uint8_t[sizeof(RDATA_FORMAT_MB)];
    RDATA_FORMAT_MB *pinfo = (RDATA_FORMAT_MB *)resinfo->rdatainfo;
    
    /* 一个<domain-name>，它规定有指定邮箱的主机 */
    memset(pinfo->madname, 0, MAXDNSNAME);
    if ( -1 == __ExpandDnsName(&offset, pinfo->madname) )
    {
        return E_RET_FAIL;
    }
    
    return E_RET_SUCCESS;
}

int32_t CDnsPacket::__Rdata2MG(DNS_RESOURCE_INFO *resinfo)
{
    int32_t offset = resinfo->rdoffset;
    
    /* 分配相应结构体的内存 */
    //resinfo->rdatainfo = new uint8_t[sizeof(RDATA_FORMAT_MG)];
    RDATA_FORMAT_MG *pinfo = (RDATA_FORMAT_MG *)resinfo->rdatainfo;
    
    /* 一个<domain-name>，它规定邮箱，该邮箱是由域名规定的邮件组的成员 */
    memset(pinfo->mgmname, 0, MAXDNSNAME);
    if ( -1 == __ExpandDnsName(&offset, pinfo->mgmname) )
    {
        return E_RET_FAIL;
    }
    
    return E_RET_SUCCESS;
}

int32_t CDnsPacket::__Rdata2MR(DNS_RESOURCE_INFO *resinfo)
{
    int32_t offset = resinfo->rdoffset;
    
    /* 分配相应结构体的内存 */
    //resinfo->rdatainfo = new uint8_t[sizeof(RDATA_FORMAT_MR)];
    RDATA_FORMAT_MR *pinfo = (RDATA_FORMAT_MR *)resinfo->rdatainfo;
    
    /* 一个<domain-name>，它规定邮箱，该邮箱是指定邮箱的适当重新命名 */
    memset(pinfo->newname, 0, MAXDNSNAME);
    if ( -1 == __ExpandDnsName(&offset, pinfo->newname) )
    {
        return E_RET_FAIL;
    }
    
    return E_RET_SUCCESS;
}

int32_t CDnsPacket::__Rdata2NULL(DNS_RESOURCE_INFO *resinfo)
{
    /* 分配相应结构体的内存 */
    //resinfo->rdatainfo = new uint8_t[sizeof(RDATA_FORMAT_NULL)];
    RDATA_FORMAT_NULL *pinfo = (RDATA_FORMAT_NULL *)resinfo->rdatainfo;
    
    /* 在RDATA字段中可以放任何东西，只要它小于等于65535个八位位组 */
    pinfo->pData = &(m_data[resinfo->rdoffset]);    /* 指向RDATA的首地址 */
    pinfo->len = resinfo->rdlen;                    /* 数据长度 */
    
    return E_RET_SUCCESS;
}

int32_t CDnsPacket::__Rdata2WKS(DNS_RESOURCE_INFO *resinfo)
{
    int32_t offset = resinfo->rdoffset;
    uint32_t *pdata = (uint32_t *)&(m_data[offset]);
    
    /* 分配相应结构体的内存 */
    //resinfo->rdatainfo = new uint8_t[sizeof(RDATA_FORMAT_WKS)];
    RDATA_FORMAT_WKS *pinfo = (RDATA_FORMAT_WKS *)resinfo->rdatainfo;
    
    /* 32位互联网地址 */
    pinfo->address = *pdata;
    pinfo->address = ntohl(pinfo->address);
    offset += sizeof(uint32_t);
    
    pinfo->protocol = m_data[offset++];     /* 8位IP 协议号 */
    pinfo->pbitmap = &(m_data[offset]);     /* 可变长度位图 */
    pinfo->bmplen = resinfo->rdlen - (offset - resinfo->rdoffset);  /* 位图长度 */
    
    return E_RET_SUCCESS;
}

int32_t CDnsPacket::__Rdata2PTR(DNS_RESOURCE_INFO *resinfo)
{
    int32_t offset = resinfo->rdoffset;
    
    /* 分配相应结构体的内存 */
    //resinfo->rdatainfo = new uint8_t[sizeof(RDATA_FORMAT_PTR)];
    RDATA_FORMAT_PTR *pinfo = (RDATA_FORMAT_PTR *)resinfo->rdatainfo;
    
    /* 一个<domain-name>，它在域名空间中指向某个位置 */
    memset(pinfo->ptrdname, 0, MAXDNSNAME);
    if ( -1 == __ExpandDnsName(&offset, pinfo->ptrdname) )
    {
        return E_RET_FAIL;
    }
    
    return E_RET_SUCCESS;
}

int32_t CDnsPacket::__Rdata2HINFO(DNS_RESOURCE_INFO *resinfo)
{
    int32_t offset = resinfo->rdoffset;
    
    /* 分配相应结构体的内存 */
    //resinfo->rdatainfo = new uint8_t[sizeof(RDATA_FORMAT_HINFO)];
    RDATA_FORMAT_HINFO *pinfo = (RDATA_FORMAT_HINFO *)resinfo->rdatainfo;
    
    /* 一个<character-string>，它规定CPU的类型 */
    pinfo->clen = m_data[offset++];
    memset(pinfo->cpu, 0, MAXCHARSTR);
    memcpy(pinfo->cpu, &m_data[offset], pinfo->clen);
    offset += pinfo->clen;
    
    /* 一个<character-string>，它规定操作系统的类型 */
    pinfo->olen = m_data[offset++];
    memset(pinfo->os, 0, MAXCHARSTR);
    memcpy(pinfo->os, &m_data[offset], pinfo->olen);
    offset += pinfo->olen;
    
    return E_RET_SUCCESS;
}

int32_t CDnsPacket::__Rdata2MINFO(DNS_RESOURCE_INFO *resinfo)
{
    int32_t offset = resinfo->rdoffset;
    
    /* 分配相应结构体的内存 */
    //resinfo->rdatainfo = new uint8_t[sizeof(RDATA_FORMAT_MINFO)];
    RDATA_FORMAT_MINFO *pinfo = (RDATA_FORMAT_MINFO *)resinfo->rdatainfo;
    
    /* 一个<domain-name>，它规定负责邮件列表或邮箱的邮箱 */
    memset(pinfo->rmailbx, 0, MAXDNSNAME);
    if ( -1 == __ExpandDnsName(&offset, pinfo->rmailbx) )
    {
        return E_RET_FAIL;
    }
    
    /* 一个<domain-name>，它规定邮箱，该邮箱将接收与邮件列表或由MINFO  RR的所有者指定的邮箱有关的出错消息 */
    memset(pinfo->emailbx, 0, MAXDNSNAME);
    if ( -1 == __ExpandDnsName(&offset, pinfo->emailbx) )
    {
        return E_RET_FAIL;
    }
    
    return E_RET_SUCCESS;
}

int32_t CDnsPacket::__Rdata2MX(DNS_RESOURCE_INFO *resinfo)
{
    int32_t offset = resinfo->rdoffset;
    
    /* 分配相应结构体的内存 */
    //resinfo->rdatainfo = new uint8_t[sizeof(RDATA_FORMAT_MX)];
    RDATA_FORMAT_MX *pinfo = (RDATA_FORMAT_MX *)resinfo->rdatainfo;
    
    /* 16位整数，它规定在同一所有者内，众多RR间，给与这个RR的优先权。值越低优先权越高 */
    pinfo->preference = m_data[offset++];
    pinfo->preference = pinfo->preference << 8 | m_data[offset++];
    
    /* 一个<domain-name>，它指定愿意为所有者名称充当邮件交换的主机 */
    memset(pinfo->exchange, 0, MAXDNSNAME);
    if ( -1 == __ExpandDnsName(&offset, pinfo->exchange) )
    {
        return E_RET_FAIL;
    }

    return E_RET_SUCCESS;
}

int32_t CDnsPacket::__Rdata2TXT(DNS_RESOURCE_INFO *resinfo)
{
    /* 分配相应结构体的内存 */
    //resinfo->rdatainfo = new uint8_t[sizeof(RDATA_FORMAT_NULL)];
    RDATA_FORMAT_NULL *pinfo = (RDATA_FORMAT_NULL *)resinfo->rdatainfo;
    
    /* 一个或多个<character-string>s */
    pinfo->pData = &(m_data[resinfo->rdoffset]);    /* 返回RDATA首地址 */
    pinfo->len = resinfo->rdlen;                    /* RDATA长度 */
    
    return E_RET_SUCCESS;
}
/* ----------解析各类RDATA数据end----------- */

#ifdef DEBUG_PRINT
/* 打印头信息 */
void CDnsPacket::PrintHeadInfo(DNS_HEAD_INFO *info)
{
    printf("id=%04x\n", info->id);
    printf("flag=%04x\n", info->flag);
    printf("qdcount=%d\n", info->qdcount);
    printf("ancount=%d\n", info->ancount);
    printf("nscount=%d\n", info->nscount);
    printf("arcount=%d\n", info->arcount);
}

/* 打印问题信息 */
void CDnsPacket::PrintQuestionInfo(DNS_QUESTION_INFO *info)
{
    printf("name=%s\n", info->name);
    printf("type=%d\n", info->type);
    printf("cls=%d\n", info->cls);
}

/* 打印资源信息 */
void CDnsPacket::PrintResourceInfo(DNS_RESOURCE_INFO *info)
{
    printf("name=%s\n", info->name);
    printf("type=%d\n", info->type);
    printf("cls=%d\n", info->cls);
    printf("ttl=%u\n", info->ttl);
    printf("rdlen=%d\n", info->rdlen);
    printf("rdoffset=%d\n", info->rdoffset);
    if ( C_IN == info->cls )
    {
        switch ( info->type )
        {
        case T_A:
            printf("rdata:\n");
            printf("address: %x\n", ((RDATA_FORMAT_A*)info->rdatainfo)->address);
            break;
        case T_NS:
            printf("rdata:\n");
            printf("nsdname: %s\n", ((RDATA_FORMAT_NS*)info->rdatainfo)->nsdname);
        case T_CNAME:
            printf("rdata:\n");
            printf("cname: %s\n", ((RDATA_FORMAT_CNAME*)info->rdatainfo)->cname);
            break;
        default:
            break;
        }
    }
}

/* 打印DNS所有信息 */
void CDnsPacket::DebugPrintDnsInfo()
{
    int i = 0;
    DNS_HEAD_INFO *ph = NULL;
    DNS_QUESTION_INFO *pq = NULL;
    DNS_RESOURCE_INFO *pr = NULL;
    
    printf("\n--------Head----------\n");
    ph = GetHeadInfo();
    PrintHeadInfo(ph);
    
    printf("\n--------Question----------\n");
    pq = GetQueriesInfo();
    for (i=0; i<ph->qdcount; i++)
    {
        printf("@@@@@@@ i=%d @@@@@@@\n", i);
        PrintQuestionInfo(&pq[i]);
    }
    
    printf("\n--------Answers-----------\n");
    pr = GetAnswersInfo();
    for (i=0; i<ph->ancount; i++)
    {
        printf("@@@@@@@ i=%d @@@@@@@\n", i);
        PrintResourceInfo(&pr[i]);
    }
    
    printf("\n--------Authors----------\n");
    pr = GetAuthorsInfo();
    for (i=0; i<ph->nscount; i++)
    {
        printf("@@@@@@@ i=%d @@@@@@@\n", i);
        PrintResourceInfo(&pr[i]);
    }
    
    printf("\n--------Additions----------\n");
    pr = GetAdditionsInfo();
    for (i=0; i<ph->arcount; i++)
    {
        printf("@@@@@@@ i=%d @@@@@@@\n", i);
        PrintResourceInfo(&pr[i]);
    }
}
#endif
